
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using Swaf.BizObj;
using Swaf.Container;

namespace Swaf.Security
{
	/// <summary>
	/// The ResourceBase class is the base class implementation of the IResource interface.  
	/// All other resource classes should inherit from this class and override any necessary 
	/// properties or methods.
	/// </summary>
	[Serializable]
	public abstract class ResourceBase : IResource, ISerializable
	{
		protected Privileges m_effectivePrivilege = Privileges.None;
		protected string m_name="";
		protected INameAddressSupport m_children=null;
		protected string m_nodeName="Resource";
	    protected string m_bizObjName=null;

		/// <summary>
		/// Basic constructor to create a new named resource.  The effectpriveprivileges for this 
		/// new resource will be defaulted to Privileges.None.
		/// </summary>
		/// <param name="name">Name of this resource</param>
		public ResourceBase(string name)
		{
			m_name=name;
			children = new FlexiMap();
		}
        protected virtual INameAddressSupport children
        {
            get
            {
                return m_children;
            }
            set
            {
                m_children = value;
            }
        }
		/// <summary>
		/// Basic constructor to create a new named resource with a predefined effectivePriviliges.
		/// </summary>
		/// <param name="name">Name of this resource</param>
		/// <param name="effPrivilege">Preset value for effectivePrivilege</param>
		public ResourceBase(string name, Privileges effPrivilege)
		{
			m_name=name;
			m_effectivePrivilege = effPrivilege;
			children = new FlexiMap();
		}
		
		/// <summary>
		/// Creates a new resource instance using an XmlNode containing information about the resource.  
		/// The XmlNode should at a minimum contain a name and effectivePrivilege attribute.
		/// </summary>
		/// <param name="ele">XmlConfiguration node containing serialized Resource information</param>
		public ResourceBase(XmlNode ele)
		{
			
			m_name = getAttributeValue(ele, "name", null);
            //Trim any trailing or leading whitespace since this is used as a key.
            if (m_name != null)
            {
                m_name = m_name.Trim();
            }
            m_bizObjName = getAttributeValue(ele, "bizObj", m_bizObjName);
            //Trim any trailing or leading whitespace
            if (m_bizObjName != null)
            {
                m_bizObjName = m_bizObjName.Trim();
            }

            m_effectivePrivilege = (Privileges)Privileges.Parse(typeof(Privileges), getAttributeValue(ele, "effectivePrivilege", "None"));
			children = new FlexiMap();
			m_nodeName = ele.Name;

			IClassFactory rscFactory = Application.currentApp.factories["Resources"];
			XmlNode res = ele.FirstChild;
			IResource resource=null;
			if (res != null)
			{
				foreach(XmlNode child in res.ChildNodes)
				{
					if (child.NodeType == XmlNodeType.Element)
					{
						try
						{
							resource = (IResource) rscFactory.createFromNickName(child.Name, child);
							children.put(resource.name,  resource);
						}
						catch(Exception e)
						{
							Application.currentApp.Log.println("Unable to create resource using node {0}. The error was {1}.", child.OuterXml, e.ToString());
						}
					}
				}
			}
		}
		
		
		/// <summary>
		/// Creates a new resource instance using an INameAddressSupport instance (normally BizObj).  
		/// This constructor is provided for a shortcut to instancing resources in the rule 
		/// associated with a resourceset and is used by the populateResourcesFromList method 
		/// of the ResourceSet class.
		/// </summary>
		/// <param name="source">INameAddressSupport instance containig information about this resource</param>
		public ResourceBase(INameAddressSupport source)
		{
			m_name = (string) source.get("name");
		    if (source.containsField("bizObj"))
		    {
                m_bizObjName = (string)source.get("bizObj");
		    }
            //Trim any trailing or leading whitespace since this is used as a key.
            if (m_name != null)
            {
                m_name = m_name.Trim();
            }
            //Trim any trailing or leading whitespace
            if (m_bizObjName != null)
            {
                m_bizObjName = m_bizObjName.Trim();
            }
            m_effectivePrivilege = (Privileges)Privileges.Parse(typeof(Privileges), (string)source.get("effectivePrivilege"));
			m_nodeName = source.GetType().Name;
			children = new FlexiMap();
			if (source.containsField("children"))
			{
				IBizObjList children_bizobjs = (IBizObjList) source.get("children");
				IClassFactory rscFactory = Application.currentApp.factories["Resources"];
				IResource resource=null;
                foreach (IBizObj child in children_bizobjs)
				{
					string name = child.type.Name;
					string type= (string) child.get("type");
					if (type.Equals(string.Empty))
						type=name;

					try
					{
						resource = (IResource) rscFactory.createFromNickName(type, child);
						children.put(resource.name,  resource);
					}
					catch(Exception e)
					{
						Application.currentApp.Log.println("Unable to create resource using BizObj {0}. The error was {1}.", child.Xml, e.ToString());
					}

				}
			}
		}
		
		/// <summary>
		/// <see cref="IResource.resources"/>
		/// </summary>
		public INameAddressSupport resources
		{
			get{return children;}
		}

		/// <summary>
		/// <see cref="IResource.clone"/>
		/// </summary>
		/// <returns></returns>
		public virtual IResource clone()
		{
			IResource dest = newInstance(m_name, m_effectivePrivilege);
			foreach(DictionaryEntry entry in (FlexiMap) this.resources)
			{
				IResource res = (IResource) entry.Value;
				dest.resources.put(res.name, res.clone());
			}
			return dest;
		}
		
		/// <summary>
		/// Helper method for retrieving an Xml Node attribute value, providing a default.
		/// </summary>
		/// <param name="ele">Node containing desired attribute</param>
		/// <param name="name">Name of attribute being requested</param>
		/// <param name="defaultVal">Deafult value to return if attribute is not found</param>
		/// <returns></returns>
		protected string getAttributeValue(XmlNode ele, string name, string defaultVal)
		{
			XmlNode att = null;
			try
			{att = ele.Attributes.GetNamedItem(name);
			}
			catch(Exception){}
			if (att == null)
				return defaultVal;
			else
				return att.Value;
		}
		/// <summary>
		/// Internal method used by base class to create a new instance of this class for cloning.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="effPrivilege"></param>
		/// <returns></returns>
		protected abstract IResource newInstance(string name, Privileges effPrivilege);
	    protected string bizObjName
	    {
            get
            {
                //If the bizobjname property has not been set, default to the resource name.
                if (m_bizObjName == null)
                {
                    return m_name;
                }
                else
                {
                    return m_bizObjName;
                }
            }
	    }
	    
	    /// <summary>
	    /// Returns an instance of the bizobj 
	    /// </summary>
	    virtual public IBizObj bizObj
	    {
	        get {
                IBizObj inst = Application.currentApp.bizObjMgr.create(bizObjName);
                inst.put("name", m_name);
                inst.put("effectivePrivilege", m_effectivePrivilege.ToString()); 
	            return inst;
	        }
	    }
		#region IResource Members

		/// <summary>
		/// <see cref="IResource.effectivePrivilege"/>
		/// </summary>
		public virtual Swaf.Security.Privileges effectivePrivilege
		{
			get
			{
				return m_effectivePrivilege;
			}
		}
		
		/// <summary>
		/// <see cref="IResource.name"/>
		/// </summary>
		public string name
		{
			get{return m_name;}	
		}
		#endregion

		#region INameAddressSupport Members

		/// <summary>
		/// <see cref="ISecurityPrincipal.containsField"/>
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <returns></returns>
		public virtual bool containsField(string nameAddress)
		{
			return children.containsField(nameAddress);
		}

		/// <summary>
		/// <see cref="ISecurityPrincipal.isGetOnly"/>
		/// </summary>
		public virtual bool isGetOnly
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// <see cref="ISecurityPrincipal.SerializationSupport"/>
		/// </summary>
		public virtual Swaf.Container.XmlSerializationSupport SerializationSupport
		{
			get
			{
				return XmlSerializationSupport.AsElement;
			}
		}

		/// <summary>
		/// <see cref="ISecurityPrincipal.put"/>
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <param name="val"></param>
		/// <param name="extraInfo"></param>
		public virtual void put(string nameAddress, object val, object extraInfo)
		{
            throw new NotImplementedException("Put is not supported for security resources.");
		}

		/// <summary>
		/// <see cref="ISecurityPrincipal.put"/>
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <param name="val"></param>
		public virtual void put(string nameAddress, object val)
		{
            throw new NotImplementedException("Put is not supported for security resources.");
		}

		public virtual string getXml(string options)
		{
			StringBuilder buffer = new StringBuilder();
			buffer.AppendFormat("<{0} name='{1}'  effectivePrivilege='{2}'/>",options, m_name, m_effectivePrivilege.ToString() );
			if (((IMap) children).Count != 0)
				buffer.Append(children.getXml("parent(Resources)"));
			return buffer.ToString();
		}

		/// <summary>
		/// Returns the actual contained resource rather than the privilege.
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <returns></returns>
		public virtual object get(string nameAddress)
		{
			if (nameAddress == null || nameAddress.Equals(String.Empty))
				return this;
            else if (((IMap)children).Count == 0)
                return Privileges.None;
            else
				return children.get(nameAddress);
		}

		/// <summary>
		/// Returns the actual contained resource rather than the privilege.
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <param name="oneArg"></param>
		/// <returns></returns>
		public virtual object get(string nameAddress, object oneArg)
		{
			if (nameAddress == null || nameAddress.Equals(String.Empty))
				return m_effectivePrivilege;
            else if (((IMap)children).Count == 0)
                return Privileges.None;
            else
				return children.get(nameAddress, oneArg);
		}

		/// <summary>
		/// Returns the actual contained resource rather than the privilege.
		/// </summary>
		/// <param name="nameAddress"></param>
		/// <param name="infoArgs"></param>
		/// <returns></returns>
		public virtual object get(string nameAddress, params object[] infoArgs)
		{
            if (nameAddress == null || nameAddress.Equals(String.Empty))
                return m_effectivePrivilege;
            else if (((IMap)children).Count == 0)
                return Privileges.None;
            else
				return children.get(nameAddress, infoArgs);
		}

		/// <summary>
		/// <see cref="INameAddressSupport.Xml"/>
		/// </summary>
		public virtual string Xml
		{
			get
			{
				return getXml("Resource");
			}
		}

		#endregion
		public ResourceBase(System.Runtime.Serialization.SerializationInfo info, StreamingContext context)
		{
			m_name=info.GetString("name");
			m_effectivePrivilege = (Privileges) Privileges.Parse(typeof(Privileges), info.GetString("privilege"));
			children = (FlexiMap) info.GetValue("children", typeof(FlexiMap));
			m_nodeName = info.GetString("node");
		}
		#region ISerializable Members

		public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, StreamingContext context)
		{
			info.AddValue("name", m_name);
			info.AddValue("privilege", m_effectivePrivilege.ToString());
			info.AddValue("children", children);
			info.AddValue("node", m_nodeName);
		}

		#endregion
		public IEnumerator GetEnumerator() { return null; }
	}
}
